package img

import (
	"bytes"
	"encoding/hex"
	"errors"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"image/png"
	"io"
	"os"
	"strings"
)

// Image 图片
type Image struct {
	ImgWide int        //原图宽
	ImgHigh int        //原图高
	Img     draw.Image //原图
	Brush   *Brush     //画笔
	Error   error      //错误信息
}

//========================= 工具方法 =========================//

func (this *Image) getStart(starts ...image.Point) (start image.Point) {
	if len(starts) > 0 {
		start = starts[0]
	}
	return
}

func (this *Image) setErr(err error) *Image {
	if err != nil {
		this.Error = err
	}
	return this
}

//========================= 写入字符 =========================//

// WriteString 写入字符串
func (this *Image) WriteString(content string, starts ...image.Point) *Image {
	return this.WriteContent(content, starts...)
}

// WriteContent 写入字符串
func (this *Image) WriteContent(content string, starts ...image.Point) *Image {
	if this.Error != nil {
		return this
	}
	start := this.getStart(starts...)
	if err := this.Brush.WriteContent(this.Img, start, content); err != nil {
		return this.setErr(err)
	}
	return this
}

//========================= 写入图片 =========================//

// WriteBytes 写入字节
func (this *Image) WriteBytes(byte []byte, starts ...image.Point) *Image {
	reader := bytes.NewReader(byte)
	//判断数据类型
	if len(byte) >= 6 {
		switch hex.EncodeToString(byte[:3]) {
		case "ffd8ff":
			return this.WriteJpegReader(reader, starts...)
		case "89504e":
			return this.WritePngReader(reader, starts...)
		case "474946":
			this.setErr(errors.New("暂不支持gif类型"))
		}
	}
	return this.setErr(errors.New("未知字节类型:" + hex.EncodeToString(byte[:6])))
}

// WriteImage 写入图片
func (this *Image) WriteImage(img image.Image, starts ...image.Point) *Image {
	if this.Error != nil {
		return this
	}
	start := this.getStart(starts...)
	for x := 0; x < img.Bounds().Max.X; x++ {
		for y := 0; y < img.Bounds().Max.Y; y++ {
			this.Img.Set(x+start.X, y+start.Y, img.At(x, y))
		}
	}
	return this
}

// WritePng 写入图片文件png
func (this *Image) WritePng(filePath string, starts ...image.Point) *Image {
	file, err := os.Open(filePath)
	if err != nil {
		return this.setErr(err)
	}
	defer file.Close()
	return this.WritePngReader(file, starts...)
}

// WritePngReader 写入图片流png
func (this *Image) WritePngReader(reader io.Reader, starts ...image.Point) *Image {
	img, err := png.Decode(reader)
	if err != nil {
		return this.setErr(err)
	}
	return this.WriteImage(img, starts...)
}

// WriteJpeg 写入图片文件jpeg
func (this *Image) WriteJpeg(filePath string, starts ...image.Point) *Image {
	file, err := os.Open(filePath)
	if err != nil {
		return this.setErr(err)
	}
	defer file.Close()
	return this.WriteJpegReader(file, starts...)
}

// WriteJpegReader 写入图片流jpeg
func (this *Image) WriteJpegReader(reader io.Reader, starts ...image.Point) *Image {
	img, err := jpeg.Decode(reader)
	if err != nil {
		return this.setErr(err)
	}
	return this.WriteImage(img, starts...)
}

//========================= 图片大小 =========================//
//
//func (this *Image) Resize(size uint) *Image {
//	if size > 0 {
//		switch this.Img.(type) {
//		case *image.RGBA:
//		case *image.Paletted:
//		}
//		this.Img = draw.Image(resize.Thumbnail(size, size, this.Img, resize.Lanczos3))
//	}
//	return this
//}

//========================= 图片水印 =========================//

//func (this *Image) WaterMark(mark image.Image) *Image {
//	srcBounds := this.Img.Bounds()
//	offset := image.Pt(srcBounds.Dx()-mark.Bounds().Dx()-10, srcBounds.Dy()-mark.Bounds().Dy()-10)
//	newImg := image.NewNRGBA(srcBounds)
//	draw.Draw(newImg, srcBounds, this.Img, image.ZP, draw.Src)
//	draw.Draw(newImg, mark.Bounds().Add(offset), mark, image.ZP, draw.Over)
//	return this
//}

//========================= 保存图片 =========================//

// Buffer 返回字节buffer
func (this *Image) Buffer() (*bytes.Buffer, error) {
	buf := bytes.NewBuffer(nil)
	err := png.Encode(buf, this.Img)
	return buf, err
}

// Bytes 返回字节
func (this *Image) Bytes() ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	err := png.Encode(buf, this.Img)
	return buf.Bytes(), err
}

// Save 保存图片
func (this *Image) Save(filePath string) error {
	if strings.Contains(filePath, ".png") {
		return this.SavePng(filePath)
	} else if strings.Contains(filePath, ".jpeg") {
		return this.SaveJpeg(filePath)
	} else if strings.Contains(filePath, ".jpg") {
		return this.SaveJpeg(filePath)
	}
	//默认png
	return this.SavePng(filePath + ".png")
}

// SavePng 保存成png
func (this *Image) SavePng(filePath string) error {
	if this.Error != nil {
		return this.Error
	}
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	return png.Encode(file, this.Img)
}

// SaveJpeg 保存成jpeg
func (this *Image) SaveJpeg(filePath string) error {
	if this.Error != nil {
		return this.Error
	}
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	return jpeg.Encode(file, this.Img, nil)
}

//========================= 拼接图片 =========================//

// JoinPng 拼接图片png
func (this *Image) JoinPng(filePath string, starts ...image.Point) *Image {
	file, err := os.Open(filePath)
	if err != nil {
		return this.setErr(err)
	}
	defer file.Close()
	return this.JoinPngReader(file, starts...)
}

// JoinPngReader 拼接图片png,reader
func (this *Image) JoinPngReader(reader io.Reader, starts ...image.Point) *Image {
	img, err := png.Decode(reader)
	if err != nil {
		return this.setErr(err)
	}
	return this.JoinImage(img, starts...)
}

// JoinJpeg 拼接图片jpg
func (this *Image) JoinJpeg(filePath string, starts ...image.Point) *Image {
	file, err := os.Open(filePath)
	if err != nil {
		return this.setErr(err)
	}
	defer file.Close()
	return this.JoinJpegReader(file, starts...)
}

// JoinJpegReader 拼接图片png,reader
func (this *Image) JoinJpegReader(reader io.Reader, starts ...image.Point) *Image {
	img, err := jpeg.Decode(reader)
	if err != nil {
		return this.setErr(err)
	}
	return this.JoinImage(img, starts...)
}

// JoinImage 拼接图片
func (this *Image) JoinImage(img image.Image, starts ...image.Point) *Image {
	if this.Error != nil {
		return this
	}
	start := this.getStart(starts...)
	//延长长度
	wide, high := this.ImgWide, this.ImgHigh
	if img.Bounds().Max.X+start.X > wide {
		wide = img.Bounds().Max.X + start.X
	}
	if img.Bounds().Max.Y+start.Y > high {
		high = img.Bounds().Max.Y + start.Y
	}
	//写入图片
	return newImage(wide, high).WriteImage(this.Img).WriteImage(img, start)
}

//========================= 图片绘画 =========================//

// SetBrushColor 设置画笔颜色
func (this *Image) SetBrushColor(color color.Color) *Image {
	this.Brush.SetFontColor(color)
	return this
}

// SetBrushRGB 设置画笔颜色
func (this *Image) SetBrushRGB(r, g, b uint8) *Image {
	this.Brush.SetFontColor(color.NRGBA{r, g, b, 255})
	return this
}

// SetBrushRGBA 设置画笔颜色
func (this *Image) SetBrushRGBA(r, g, b, a uint8) *Image {
	this.Brush.SetFontColor(color.NRGBA{r, g, b, a})
	return this
}

// SetBrushSize 设置画笔大小
func (this *Image) SetBrushSize(size int) *Image {
	this.Brush.SetFontSize(size)
	return this
}

// DrawPoint 画点
func (this *Image) DrawPoint(site image.Point) *Image {
	if this.Error != nil {
		return this
	}
	this.Brush.DrawPoint(this.Img, site)
	return this
}

// DrawCircle 画圆
func (this *Image) DrawCircle(centre image.Point, radii int) *Image {
	if this.Error != nil {
		return this
	}
	this.Brush.DrawCircle(this.Img, centre, radii)
	return this
}

// DrawRectangle 画矩形
func (this *Image) DrawRectangle(start image.Point, wide, high int) *Image {
	if this.Error != nil {
		return this
	}
	this.Brush.DrawRectangle(this.Img, start, wide, high)
	return this
}

// newImage新建图片
// @wide,宽
// @high,高
// @backColor,背景颜色
func newImage(wide, high int, backColor ...color.Color) *Image {
	data := &Image{
		ImgWide: wide,
		ImgHigh: high,
	}
	brush, err := newBrush()
	if err != nil {
		return data.setErr(err)
	}
	alpha := image.NewNRGBA(image.Rect(0, 0, wide, high))
	if len(backColor) > 0 {
		for x := 0; x < wide; x++ {
			for y := 0; y < high; y++ {
				alpha.Set(x, y, backColor[0])
			}
		}
	}
	data.Brush = brush
	data.Img = alpha
	return data
}
